#include "DonorList.h"
#include "Database.h"

#include "iostream"
#include "set"
#include "string"
using namespace std;

Node::Node(DonorType newDonor, Node *newNext) {
    this->donor = newDonor;
    this->next = newNext;
}

void Node::setDonor(const DonorType& newDonor) {
    this->donor = newDonor;
}

void Node::setNext(Node *newNext) {
    this->next = newNext;
}

DonorType Node::getDonor() {
    return this->donor;
}

Node * Node::getNext() const {
    return this->next;
}

DonorList::DonorList() {
    this->first = nullptr;
    this->last = nullptr;
    this->count = 0;
}

void DonorList::addDonor(
        const string &newFirst,
        const string &newLast,
        int newMembershipNo,
        double donation) {
    if (!this->searchID(newMembershipNo)) {
        Node *node = new Node(
                DonorType{newFirst, newLast, newMembershipNo, donation},
                nullptr);
        if (this->count == 0) {
            this->first = node;
            this->last = node;
        } else {
            if (this->first->getDonor().getMembershipNo() > newMembershipNo) {
                node->setNext(this->first);
                this->first = node;
            } else {
                Node *temp = this->first;
                while (temp->getNext() != nullptr) {
                    if (temp->getDonor().getMembershipNo() < newMembershipNo
                        && temp->getNext()->getDonor().getMembershipNo() > newMembershipNo) {
                        break;
                    }
                    temp = temp->getNext();
                }
                if (temp->getNext() != nullptr) {
                    Node *next = temp->getNext();
                    temp->setNext(node);
                    node->setNext(next);
                    if (this->last->getNext() != nullptr) {
                        this->last = this->last->getNext();
                    }
                } else {
                    this->last->setNext(node);
                    this->last = this->last->getNext();
                }
            }
        }
        this->count ++;
    }
}

void DonorList::createList() {
    set<DonorType> donors = getData();
    if (donors.empty()) {
        cout << "Database has no data." << endl;
    } else {
        auto iter = donors.begin();
        while (iter != donors.end()) {
            this->addDonor(
                    iter->getFirstName(),
                    iter->getLastName(),
                    iter->getMembershipNo(),
                    iter->getAmountDonated());
            iter++;
        }
    }
}

int DonorList::getNoOfDonors() const {
    return this->count;
}

double DonorList::getTotalDonations() const {
    Node *temp = this->first;
    double totalDonation = 0;
    while (temp != nullptr) {
        totalDonation += temp->getDonor().getAmountDonated();
        temp = temp->getNext();
    }
    return totalDonation;
}

bool DonorList::isEmpty() const {
    return this->count == 0;
}

bool DonorList::searchID(int membershipNo) const {
    Node *temp = this->first;
    while (temp != nullptr) {
        if (temp->getDonor().getMembershipNo() == membershipNo) {
            break;
        }
        temp = temp->getNext();
    }
    return temp != nullptr;
}

void DonorList::deleteDonor(int membershipNo) {
    if (this->count == 0) {
        cout << "Donor is not in the list." << endl;
    } else {
        Node *temp = this->first;
        if (this->first->getDonor().getMembershipNo() == membershipNo) {
            Node *temp = this->first;
            this->first = this->first->getNext();
            delete temp;
            temp = nullptr;
            this->count --;
        } else {
            while (temp->getNext() != nullptr &&
                temp->getNext()->getDonor().getMembershipNo() != membershipNo) {
                temp = temp->getNext();
            }
            if (temp->getNext() == nullptr) {
                cout << "Donor is not in the list." << endl;
            } else {
                Node *deleteItem = temp->getNext();
                temp->setNext(deleteItem->getNext());
                this->count --;
                delete deleteItem;
                deleteItem = nullptr;
            }
        }
    }
}

void DonorList::printAllDonors() const {
    Node *temp = this->first;
    while (temp != nullptr) {
        temp->getDonor().printMemberInfo();
        temp = temp->getNext();
    }
}

void DonorList::printAllDonations() const {
    Node *temp = this->first;
    while (temp != nullptr) {
        temp->getDonor().printDonation();
        temp = temp->getNext();
    }
}

void DonorList::clearList() {
    this->count = 0;
    while (this->first != nullptr) {
        Node *temp = this->first->getNext();
        delete this->first;
        this->first = temp;
    }
}

DonorList::~DonorList() {
    this->clearList();
}





